
#include "painlessMesh.h"
#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555
#define KEY 13
#define TF_CHECK 15
painlessMesh mesh;
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128    // OLED display width, in pixels
#define SCREEN_HEIGHT 64    // OLED display height, in pixels
#define OLED_RESET -1       // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#include "FS.h"
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
String msg = "";
File myFile;
bool serReceived = 0;
unsigned long mills;
#define DATA_SIZE 26 // 26 bytes is a lower than RX FIFO size (127 bytes)
#define BAUD 4800    // Any baudrate from 300 to 115200
#define TEST_UART 1  // Serial1 will be used for the loopback testing with different RX FIFO FULL values
#define RXPIN 17     // GPIO 4 => RX for Serial1
#define TXPIN 16     // GPIO 5 => TX for Serial1

#include <Wire.h>
#define RX8018_ADDR 0x32
char fileName[30];
struct dateTime
{
    u_char year;
    u_char month;
    u_char date;
    u_char day;
    u_char hour;
    u_char minute;
    u_char second;
};
dateTime getDateTime()
{
    u_char ti[7], i;
    dateTime dt;
    Wire.beginTransmission(RX8018_ADDR); // 开启发送
    Wire.write(0x10);                    // 写入 DS1307 秒地址
    Wire.endTransmission();              //  结束发送
    Wire.requestFrom(RX8018_ADDR, 7);    // 请求 DS1307 一个字节
    i = 0;
    while (Wire.available())
    {                                          // 可否获取1个数据
        ti[i++] = bcd2dec(Wire.read() & 0x7F); // 读取 DS1307 秒
    }
    dt.year = ti[6];
    dt.month = ti[5];
    dt.date = ti[4];
    dt.day = ti[3];
    dt.hour = ti[2];
    dt.minute = ti[1];
    dt.second = ti[0];
    return dt;
}
void setTime(dateTime dt)
{
    Wire.beginTransmission(RX8018_ADDR); // 开启发送
    Wire.write(0x10);                    // 写入 DS1307 秒地址

    Wire.write(dec2bcd(dt.second));
    Wire.write(dec2bcd(dt.minute));
    Wire.write(dec2bcd(dt.hour));
    Wire.write(dec2bcd(dt.day));
    Wire.write(dec2bcd(dt.date));
    Wire.write(dec2bcd(dt.month));
    Wire.write(dec2bcd(dt.year));
    Wire.endTransmission();
}
SimpleList<uint32_t> nodes;
int band[] = {4800, 9600, 38400};
bool changBAUD = 0;
int bandNum = 0;
void sendMessage(String msg)
{
    mesh.sendBroadcast(msg);
    Serial.printf("T:%s\n", msg.c_str());
}
void receivedCallback(uint32_t from, String &msg)
{
    Serial.printf("R[%u]:%s\n", from, msg.c_str());
}
void newConnectionCallback(uint32_t nodeId)
{
    Serial.printf("New Connection: %u\n", nodeId);
}

void changedConnectionCallback()
{
    Serial.printf("Changed connections\n");
    nodes = mesh.getNodeList();
    Serial.printf("Num nodes: %d\n", nodes.size());
    Serial.printf("Connection list:");
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Connection list:");
    SimpleList<uint32_t>::iterator node = nodes.begin();
    while (node != nodes.end())
    {
        Serial.printf(" %u", *node);
        display.println(*node);
        node++;
    }
    display.display();
    Serial.println();
}
void nodeTimeAdjustedCallback(int32_t offset)
{
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void Callback1(void)
{
    char talker[10], heading[10], tMsg[10];
    msg = Serial1.readStringUntil('\n');
    serReceived = 1;
    if (display.getCursorY() > 56)
    {
        display.clearDisplay();
        display.setCursor(0, 0);
    }
    //    display.setTextSize(1);
    //    display.setTextColor(SSD1306_WHITE);
    display.println(msg);
    display.display();
    Serial.printf("S1R:%s\n", msg.c_str());
    sscanf(msg.c_str(), "$%*c%*c%[^,],%[^,],%*s", talker, heading);
    if (strcmp(talker, "HDT") == 0)
    {
        sprintf(tMsg, "HDT:%s", heading);
        mesh.sendBroadcast(tMsg);
        Serial.printf("[MESH T]:%s\n", tMsg);
    }
    if (strcmp(talker, "ROT") == 0)
    {
        if (heading[0] != '-')
        {
            mesh.sendBroadcast("ROT:S");
            Serial.println("[MESH T]:ROT:S");
        }
        else
        {
            mesh.sendBroadcast("ROT:P");
            Serial.println("[MESH T]:ROT:P");
        }
    }
}
void Callback(void)
{
    String msg = "";
    char talker[10], heading[10], tMsg[10];
    if (Serial.available())
    {
        msg = Serial.readStringUntil('\n');
    }
    Serial.printf("S0R:%s\n", msg.c_str());
    sscanf(msg.c_str(), "$%*c%*c%[^,],%[^,],%*s", talker, heading);
    if (strcmp(talker, "HDT") == 0)
    {
        sprintf(tMsg, "HDT:%s°", heading);
        mesh.sendBroadcast(tMsg);
        Serial.printf("[MESH T]:%s\n", tMsg);
    }
    if (strcmp(talker, "ROT") == 0)
    {
        if (heading[0] != '-')
        {
            mesh.sendBroadcast("ROT:S");
            Serial.println("[MESH T]:ROT:S");
        }
        else
        {
            mesh.sendBroadcast("ROT:P");
            Serial.println("[MESH T]:ROT:P");
        }
    }
}
void writeFile(fs::FS &fs, const char *path, const char *message)
{
    Serial.printf("Writing file: %s\n", path);
    File file = fs.open(path, FILE_WRITE);
    if (!file)
    {
        Serial.println("Failed to open file for writing");
        return;
    }
    if (file.print(message))
    {
        Serial.println("File written");
    }
    else
    {
        Serial.println("Write failed");
    }
    file.close();
}
bool appendFile(fs::FS &fs, const char *path, const char *message)
{
    Serial.printf("Appending to file: %s\n", path);
    File file = fs.open(path, FILE_APPEND);
    if (!file)
    {
        Serial.println("Failed to open file for appending");
        return 0;
    }
    else
    {
        if (file.print(message))
        {
            Serial.println("Message appended");
        }
        else
        {
            Serial.println("Append failed");
        }
        file.close();
    }

    return 1;
}
void callBackInterKey()
{
    changBAUD = 1;
}
void setup()
{
    Serial.begin(115200);
    pinMode(KEY, INPUT_PULLUP);
    pinMode(TF_CHECK, INPUT);
    delay(100);
    Serial.onReceive(Callback);
    Serial.printf("\n\n================================\nTest Case #6\n================================\n");
    display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
    display.setRotation(0);
    display.setTextSize(2);
    display.clearDisplay();
    display.display(); // Show i
    display.setCursor(0, 0);
    display.setTextColor(SSD1306_WHITE);
    display.printf("SET BAUD:\n%d\n", band[bandNum]);
    display.display();
    mills = millis();
    while (millis() - mills < 5000)
    {
        if (digitalRead(KEY) == 0)
        {
            delay(5);
            if (digitalRead(KEY) == 0)
            {
                while (digitalRead(KEY) == 0)
                    mills = millis();
                bandNum++;
                bandNum = bandNum % 3;
                display.clearDisplay();
                display.setCursor(0, 0);
                display.setTextColor(SSD1306_WHITE);
                display.printf("SET BAUD:\n%d\n", band[bandNum]);
                display.display();
            }
        }
    }
    display.clearDisplay();
    display.setTextSize(1);
    display.display(); // Show i
    display.setCursor(0, 0);
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(1);
    if (digitalRead(TF_CHECK) == 0)
    {
        if (!SD.begin(5))
        {
            Serial.println("Card Mount Failed");
            return;
        }
        else
        {
            dateTime dt = getDateTime();
            sprintf(fileName, "/Record%02d%02d%02d-%02d%02d%02d.txt",
                    dt.year, dt.month, dt.date, dt.hour, dt.minute, dt.second);
            Serial.printf("File name is %s", fileName);
            //   display.printf("%02d-%02d-%02d %02d:%02d:%02d", fileName);
            display.printf("File name:\n%s\n", fileName);
            writeFile(SD, fileName, msg.c_str());
        }
    }
    display.display();

    display.println("Connect to MESH...");
    display.display();
    mesh.setDebugMsgTypes(ERROR | STARTUP); // set before init() so that you can see startup messages
    mesh.init(MESH_PREFIX, MESH_PASSWORD, MESH_PORT);
    mesh.onReceive(&receivedCallback);
    mesh.onNewConnection(&newConnectionCallback);
    mesh.onChangedConnections(&changedConnectionCallback);
    mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
    Serial1.begin(band[bandNum], SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3                             //    Serial1.onReceive(Callback);
                                                            //   Serial1.onReceive(Callback1);
    Serial1.setRxBufferSize(255);

    delay(1000);
}
uint8_t dec2bcd(uint8_t dec)
{
    return ((dec / 10 * 16) + (dec % 10));
}

uint8_t bcd2dec(uint8_t bcd)
{
    return ((bcd / 16 * 10) + (bcd % 16));
}
void loop()
{
    mesh.update();
    if (Serial1.available())
        Callback1();
    if (digitalRead(TF_CHECK) == 0)
        if (serReceived == 1)
        {
            if (appendFile(SD, fileName, msg.c_str()) == 0)
                SD.begin(5);
            //   writeFile(SD, fileName, msg.c_str());

            serReceived = 0;
        }
    if (millis() % 5000 == 0)
        mesh.sendBroadcast("test");
}
